package com.facebook.app.server.facebook;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;

import javax.jdo.PersistenceManager;

import com.facebook.app.shared.facebookData.FacebookFriend;
import com.facebook.app.shared.facebookData.FacebookLike;
import com.google.gson.Gson;

public class FacebookImporter {
	
	private static class FriendData {
		
		private FacebookFriend[] data = new FacebookFriend[0];
		// to avoid a NullPointerException if the user has just logged out, but the Facebook cookie is still "alive".
		// TODO has to be fixed
	}
	
	private static class LikeData {
		
		private FacebookLike[] data;
	}
	
	private static final int MAX_NUMBER_OF_CONNECTION_ERRORS = 20;

	private final String baseUrl = "https://graph.facebook.com";
	private final String accessToken;
	private final Gson gson = new Gson();

	private int numberOfConnectionErrors = 0;

	public FacebookImporter(String accessToken) {
		this.accessToken = accessToken;
	}
	
	private Reader downloadData(String url) {
		if(numberOfConnectionErrors > MAX_NUMBER_OF_CONNECTION_ERRORS) {
			System.out.println("Connection errors have exceeded limit of " + MAX_NUMBER_OF_CONNECTION_ERRORS);
			return null;
		}
		
		try {
			URL dataURL = new URL(url);
			return new InputStreamReader(dataURL.openStream());
			
		} catch (MalformedURLException e) {
			e.printStackTrace();
			return null;
			
		} catch (IOException e) {
			System.out.println("Catched IOE : " + e.toString());
			// TODO Check whether IOE is cause by open URL connection.
			numberOfConnectionErrors++;
			return downloadData(url);
		}
	}
	
	private FacebookFriend[] importFriendsForFriend(FacebookFriend friend) {

		StringBuilder req = new StringBuilder(baseUrl);
		req.append("/");
		req.append(friend.getId());
		req.append("/friends");
		try {
			req.append("?access_token="
					+ URLEncoder.encode(accessToken, "UTF-8"));
		} catch (UnsupportedEncodingException e1) {
			e1.printStackTrace();
		}

		FriendData friendData = gson.fromJson(downloadData(req.toString()), FriendData.class);
		return friendData.data;
	}

	FacebookLike[] importLikesForFriend(FacebookFriend friend) {

		StringBuilder req = new StringBuilder(baseUrl);
		req.append("/");
		req.append(friend.getId());
		req.append("/likes");
		try {
			req.append("?access_token="
					+ URLEncoder.encode(accessToken, "UTF-8"));
		} catch (UnsupportedEncodingException e1) {
			e1.printStackTrace();
		}

		LikeData likeData = gson.fromJson(downloadData(req.toString()), LikeData.class);
		return likeData.data;
	}

	public FacebookFriend[] importFriends() {

		StringBuilder req = new StringBuilder(baseUrl);
		req.append("/me?access_token=");
		try {
			req.append(URLEncoder.encode(accessToken, "UTF-8"));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}

		FacebookFriend me = gson.fromJson(downloadData(req.toString()), FacebookFriend.class);
		
		FacebookFriend[] myFriends = importFriendsForFriend(me);
		FacebookFriend[] friendsWithMe = new FacebookFriend[myFriends.length + 1];

		for (int i = 0; i < myFriends.length; i++) {
			friendsWithMe[i] = myFriends[i];
		}

		friendsWithMe[friendsWithMe.length - 1] = me;
		return friendsWithMe;
	}

	/**
	 * Imports the FacebookLikes for a certain number of FacebookFriends
	 * and saves those friends on the datastore.
	 * 
	 * @param friends
	 */
	public void importAndSaveFacebookData(FacebookFriend[] friends) {
		
		for (FacebookFriend friend: friends) {
			System.out.print(".");
			friend.setLikesWithArray(importLikesForFriend(friend));
		}

		PersistenceManager pm = PersistenceManagerFactorySingleton
				.getPersistenceManagerFactoryInstance().getPersistenceManager();

		try {
			pm.makePersistentAll(friends);

		} finally {
			pm.close();
		}
	}

}
